import re
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from tkinter.scrolledtext import ScrolledText


class TexCitationExtractor:
    def __init__(self, root):
        self.root = root
        self.root.title("TeX引用ID提取器")
        self.root.geometry("800x600")
        self.root.minsize(700, 500)

        # 存储所选文件的路径和顺序
        self.selected_files = []

        # 创建界面
        self.create_widgets()

    def create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 文件选择部分
        file_frame = ttk.LabelFrame(main_frame, text="选择TeX文件", padding="10")
        file_frame.pack(fill=tk.X, pady=5)

        # 添加文件按钮
        ttk.Button(file_frame, text="添加文件", command=self.add_files).pack(side=tk.LEFT, padx=5)

        # 清除所选文件按钮
        ttk.Button(file_frame, text="清除所选", command=self.clear_files).pack(side=tk.LEFT, padx=5)

        # 文件列表框架
        list_frame = ttk.LabelFrame(main_frame, text="已选择的文件", padding="10")
        list_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        # 文件列表及其滚动条
        list_subframe = ttk.Frame(list_frame)
        list_subframe.pack(fill=tk.BOTH, expand=True)

        self.files_listbox = tk.Listbox(list_subframe, selectmode=tk.EXTENDED)
        self.files_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        files_scrollbar = ttk.Scrollbar(list_subframe, orient=tk.VERTICAL, command=self.files_listbox.yview)
        files_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.files_listbox.config(yscrollcommand=files_scrollbar.set)

        # 文件排序按钮
        sort_frame = ttk.Frame(list_frame)
        sort_frame.pack(fill=tk.X, pady=5)

        ttk.Button(sort_frame, text="上移", command=self.move_up).pack(side=tk.LEFT, padx=5)
        ttk.Button(sort_frame, text="下移", command=self.move_down).pack(side=tk.LEFT, padx=5)

        # 提取按钮
        extract_frame = ttk.Frame(main_frame)
        extract_frame.pack(fill=tk.X, pady=5)

        ttk.Button(extract_frame, text="提取引用ID", command=self.extract_citations).pack(pady=10)

        # 结果显示区域
        result_frame = ttk.LabelFrame(main_frame, text="提取的引用ID", padding="10")
        result_frame.pack(fill=tk.BOTH, expand=True, pady=5)

        self.result_text = ScrolledText(result_frame, wrap=tk.WORD, height=10)
        self.result_text.pack(fill=tk.BOTH, expand=True)

        # 保存结果按钮
        save_frame = ttk.Frame(main_frame)
        save_frame.pack(fill=tk.X, pady=5)

        ttk.Button(save_frame, text="保存到文件", command=self.save_to_file).pack(pady=5)

    def add_files(self):
        """添加TeX文件到列表"""
        files = filedialog.askopenfilenames(
            title="选择TeX文件",
            filetypes=[("TeX文件", "*.tex"), ("所有文件", "*.*")]
        )

        if files:
            for file in files:
                if file not in self.selected_files:
                    self.selected_files.append(file)
                    self.files_listbox.insert(tk.END, os.path.basename(file))

    def clear_files(self):
        """清除所有选择的文件"""
        self.selected_files = []
        self.files_listbox.delete(0, tk.END)

    def move_up(self):
        """将所选文件在列表中上移"""
        selected_indices = self.files_listbox.curselection()
        if not selected_indices or selected_indices[0] == 0:
            return

        for idx in selected_indices:
            # 交换文件列表中的位置
            self.selected_files[idx], self.selected_files[idx - 1] = self.selected_files[idx - 1], self.selected_files[
                idx]

            # 更新UI列表
            text = self.files_listbox.get(idx)
            self.files_listbox.delete(idx)
            self.files_listbox.insert(idx - 1, text)
            self.files_listbox.selection_set(idx - 1)

    def move_down(self):
        """将所选文件在列表中下移"""
        selected_indices = list(self.files_listbox.curselection())
        if not selected_indices or selected_indices[-1] == self.files_listbox.size() - 1:
            return

        # 倒序处理，避免索引变化导致的问题
        for idx in reversed(selected_indices):
            # 交换文件列表中的位置
            self.selected_files[idx], self.selected_files[idx + 1] = self.selected_files[idx + 1], self.selected_files[
                idx]

            # 更新UI列表
            text = self.files_listbox.get(idx)
            self.files_listbox.delete(idx)
            self.files_listbox.insert(idx + 1, text)
            self.files_listbox.selection_set(idx + 1)

    def extract_citations(self):
        """从选定的TeX文件中提取引用ID"""
        if not self.selected_files:
            messagebox.showwarning("警告", "请先选择TeX文件")
            return

        citation_ids = []

        # 按照列表顺序处理每个文件
        for file_path in self.selected_files:
            try:
                with open(file_path, 'r', encoding='utf-8') as file:
                    content = file.read()

                    # 使用正则表达式提取cite{...}中的引用ID
                    # 支持多种引用形式，如\cite{id}, \citep{id}, \citet{id}等
                    cite_pattern = r'\\(?:cite|citep|citet|citealp|citealt|citeauthor|citeyear|citeyearpar|parencite|textcite|autocite|footcite|fullcite)\{([^}]+)\}'

                    matches = re.findall(cite_pattern, content)
                    for match in matches:
                        # 处理可能的多个ID，例如\cite{id1,id2,id3}
                        ids = [id.strip() for id in match.split(',')]
                        citation_ids.extend(ids)
            except Exception as e:
                messagebox.showerror("错误", f"处理文件 {os.path.basename(file_path)} 时发生错误：\n{str(e)}")

        # 移除重复ID并保持顺序
        unique_ids = []
        for id in citation_ids:
            if id not in unique_ids:
                unique_ids.append(id)

        # 显示结果
        self.result_text.delete(1.0, tk.END)
        for id in unique_ids:
            self.result_text.insert(tk.END, id + '\n')

        # 显示统计信息
        messagebox.showinfo("提取完成", f"共提取出 {len(unique_ids)} 个唯一引用ID")

    def save_to_file(self):
        """将提取的引用ID保存到文件"""
        content = self.result_text.get(1.0, tk.END).strip()
        if not content:
            messagebox.showwarning("警告", "没有可保存的内容")
            return

        file_path = filedialog.asksaveasfilename(
            title="保存引用ID列表",
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )

        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as file:
                    file.write(content)
                messagebox.showinfo("成功", f"引用ID列表已保存到：\n{file_path}")
            except Exception as e:
                messagebox.showerror("错误", f"保存文件时发生错误：\n{str(e)}")


if __name__ == "__main__":
    root = tk.Tk()
    app = TexCitationExtractor(root)
    root.mainloop()